package com.ecloud.gateway.exception;

import javax.annotation.PostConstruct;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.ecloud.common.base.result.ResultBuilder;
import com.ecloud.common.base.result.ResultStatus;

import reactor.core.publisher.Mono;

/**
 * Sentinel自定义异常处理器
 *
 * @author LiuGangQiang Create in 2021/06/18
 */
@Order(-1)
@Configuration
public class SentinelExceptionHandler {

    /**
     * 初始化配置
     *
     * @author LiuGangQiang Create in 2021/06/20
     */
    @PostConstruct
    public void init() {
        /* 初始化异常处理策略 */
        initBlockHandler();
    }

    /**
     * 初始化Sentinel异常处理
     *
     * @author LiuGangQiang Create in 2021/06/20
     */
    private void initBlockHandler() {
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable throwable) {
                if (throwable instanceof FlowException) {
                    /* 接口限流异常 */
                    return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                            .contentType(MediaType.APPLICATION_JSON)
                            .bodyValue(ResultBuilder.build(ResultStatus.TOO_MANY_REQUESTS));
                } else if (throwable instanceof ParamFlowException) {
                    /* 热点限流异常 */
                    return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                            .contentType(MediaType.APPLICATION_JSON)
                            .bodyValue(ResultBuilder.build(ResultStatus.HOT_PARAM_FLOW));
                } else if (throwable instanceof DegradeException) {
                    /* 服务降级异常 */
                    return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE)
                            .contentType(MediaType.APPLICATION_JSON)
                            .bodyValue(ResultBuilder.build(ResultStatus.SERVICE_DEGRADE));
                } else if (throwable instanceof SystemBlockException) {
                    /* 系统保护异常 */
                    return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE)
                            .contentType(MediaType.APPLICATION_JSON)
                            .bodyValue(ResultBuilder.build(ResultStatus.SYSTEM_BLOCK));
                } else if (throwable instanceof AuthorityException) {
                    /* 授权规则异常 */
                    return ServerResponse.status(HttpStatus.FORBIDDEN)
                            .contentType(MediaType.APPLICATION_JSON)
                            .bodyValue(ResultBuilder.build(ResultStatus.AUTHORITY));
                } else {
                    /* 其他未知异常 */
                    return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
                            .contentType(MediaType.APPLICATION_JSON)
                            .bodyValue(ResultBuilder.build(ResultStatus.SYSTEM_ERROR));
                }
            }
        });
    }
}
